/*---------------------------------------------------------------------
 * File name: hal_pwm.cpp
 *
 * Copyright (c) <2020-2022>, <ChenLong>
 *
 * All rights reserved.
 *
 * Author: ChenLong
 * Email: worldlong@foxmail.com
 *--------------------------------------------------------------------*/
#include "gd32f10x.h"
#include "hal_pwm.h"
#include "hal_config.h"
#if defined(USING_RT_THREAD)
#include <rtthread.h>
#endif
/*****************************************************************************
 *                          PWM Out
 *****************************************************************************/
/*
*/
bool HAL_PWMOut::init(HAL_Timer *timer0, uint32_t cfg0)
{
  timer = timer0;
  cfg = cfg0;
  return config(cfg);
}
/*
*/
bool HAL_PWMOut::config(uint32_t cfg0)
{
  cfg &= ~HPWM_CFG_MASK;
  cfg |= cfg0 & HPWM_CFG_MASK;
  	
  /* OC config */
  timer_oc_parameter_struct timer_ocintpara;
  
  timer_ocintpara.outputstate  = TIMER_CCX_ENABLE;
  timer_ocintpara.outputnstate = TIMER_CCXN_ENABLE;
  //OCP
  uint32_t tmp = HPWM_CFG_EXTRACT(cfg, OCP);
  if(tmp == HPWM_OCP(HIGH)) { 
    timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_HIGH;
  } else { 
    timer_ocintpara.ocpolarity   = TIMER_OC_POLARITY_LOW;
  }
  //OCNP
  tmp = HPWM_CFG_EXTRACT(cfg, OCNP);
  if(tmp == HPWM_OCNP(HIGH)) { 
    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_HIGH;
  } else { 
    timer_ocintpara.ocnpolarity  = TIMER_OCN_POLARITY_LOW;
  }
  //OCIDS
  tmp = HPWM_CFG_EXTRACT(cfg, OCIDS);
  if(tmp == HPWM_OCIDS(SET)) { 
    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_HIGH;
  } else {
    timer_ocintpara.ocidlestate  = TIMER_OC_IDLE_STATE_LOW;
  }
  //OCNIDS
  tmp = HPWM_CFG_EXTRACT(cfg, OCNIDS);
  if(tmp == HPWM_OCNIDS(SET)) { 
    timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_HIGH;
  } else {
    timer_ocintpara.ocidlestate  = TIMER_OCN_IDLE_STATE_LOW;
  }
  
  //Config
  uint32_t mode = HPWM_CFG_EXTRACT(cfg, MODE);
  tmp = HPWM_CFG_EXTRACT(cfg, CH);
  if(tmp & HPWM_CH(0)) { 
    timer_channel_output_config(timer->port, TIMER_CH_0, &timer_ocintpara);
    timer_channel_output_pulse_value_config(timer->port, TIMER_CH_0, 0);
    if(mode == HPWM_MODE_0) {
      timer_channel_output_mode_config(timer->port, TIMER_CH_0, TIMER_OC_MODE_PWM0);
    } else  {
      timer_channel_output_mode_config(timer->port, TIMER_CH_0, TIMER_OC_MODE_PWM1);
    }
    timer_channel_output_shadow_config(timer->port, TIMER_CH_0, TIMER_OC_SHADOW_ENABLE);
  }
  if(tmp & HPWM_CH(1)) { 
    timer_channel_output_config(timer->port, TIMER_CH_1, &timer_ocintpara);
    timer_channel_output_pulse_value_config(timer->port, TIMER_CH_1, 0);
    if(mode == HPWM_MODE_0) {
      timer_channel_output_mode_config(timer->port, TIMER_CH_1, TIMER_OC_MODE_PWM0);
    } else  {
      timer_channel_output_mode_config(timer->port, TIMER_CH_1, TIMER_OC_MODE_PWM1);
    }
    timer_channel_output_shadow_config(timer->port, TIMER_CH_1, TIMER_OC_SHADOW_ENABLE);
  }
  if(tmp & HPWM_CH(2)) { 
    timer_channel_output_config(timer->port, TIMER_CH_2, &timer_ocintpara);
    timer_channel_output_pulse_value_config(timer->port, TIMER_CH_2, 0);
    if(mode == HPWM_MODE_0) {
      timer_channel_output_mode_config(timer->port, TIMER_CH_2, TIMER_OC_MODE_PWM0);
    } else  {
      timer_channel_output_mode_config(timer->port, TIMER_CH_2, TIMER_OC_MODE_PWM1);
    }
    timer_channel_output_shadow_config(timer->port, TIMER_CH_2, TIMER_OC_SHADOW_ENABLE);
  }
  if(tmp & HPWM_CH(3)) { 
    timer_channel_output_config(timer->port, TIMER_CH_3, &timer_ocintpara);
    timer_channel_output_pulse_value_config(timer->port, TIMER_CH_3, 0);
    if(mode == HPWM_MODE_0) {
      timer_channel_output_mode_config(timer->port, TIMER_CH_3, TIMER_OC_MODE_PWM0);
    } else  {
      timer_channel_output_mode_config(timer->port, TIMER_CH_3, TIMER_OC_MODE_PWM1);
    }
    timer_channel_output_shadow_config(timer->port, TIMER_CH_3, TIMER_OC_SHADOW_ENABLE);
  }
  return true;
}
/*
*/
void HAL_PWMOut::set_freq(int freq)
{
  if(freq == 0) {
    TIMER_CTL0(timer->port) &= ~BIT(0);  //disable timer counter
  } else {
    timer->period = timer->clock / freq;
    TIMER_CAR(timer->port) = (uint32_t)timer->period - 1;
    set_percent100(percent100);
    TIMER_CTL0(timer->port) |= BIT(0);  //enable timer counter
  }
}
/*
*/
void HAL_PWMOut::set_freq_width(int freq, int width)
{
  if(freq == 0) {
    TIMER_CTL0(timer->port) &= ~BIT(0);  //disable timer counter
  } else {
    timer->period = timer->clock / freq;
    uint16_t pulse_us = 1000000/timer->clock;
    uint16_t pulse = (width + pulse_us - 1) / pulse_us;
    TIMER_CAR(timer->port) = (uint32_t)timer->period - 1;
    TIMER_CH0CV(timer->port) = (uint32_t)pulse;
    TIMER_CH1CV(timer->port) = (uint32_t)pulse;
    TIMER_CH2CV(timer->port) = (uint32_t)pulse;
    TIMER_CH3CV(timer->port) = (uint32_t)pulse;
    TIMER_CTL0(timer->port) |= BIT(0);  //enable timer counter
  }
}
/*
*/
void HAL_PWMOut::set_percent(int index, float percent0)
{
  percent[index] = percent0;
  TIMER_CH0CV(timer->port) = (uint32_t)(timer->period * percent[0]);
  TIMER_CH1CV(timer->port) = (uint32_t)(timer->period * percent[1]);
  TIMER_CH2CV(timer->port) = (uint32_t)(timer->period * percent[2]);
  TIMER_CH3CV(timer->port) = (uint32_t)(timer->period * percent[3]);
}
/*
*/
void HAL_PWMOut::set_percent(float *percent0)
{
  memcpy(percent, percent0, sizeof(float)*4);

  TIMER_CH0CV(timer->port) = (uint32_t)(timer->period * percent[0]);
  TIMER_CH1CV(timer->port) = (uint32_t)(timer->period * percent[1]);
  TIMER_CH2CV(timer->port) = (uint32_t)(timer->period * percent[2]);
  TIMER_CH3CV(timer->port) = (uint32_t)(timer->period * percent[3]);
}
/*
*/
void HAL_PWMOut::set_percent100(int index, int percent0)
{
  percent100[index] = percent0;
  TIMER_CH0CV(timer->port) = (uint32_t)(timer->period * percent100[0] / 100);
  TIMER_CH1CV(timer->port) = (uint32_t)(timer->period * percent100[1] / 100);
  TIMER_CH2CV(timer->port) = (uint32_t)(timer->period * percent100[2] / 100);
  TIMER_CH3CV(timer->port) = (uint32_t)(timer->period * percent100[3] / 100);
}
/*
*/
void HAL_PWMOut::set_percent100(int *percent0)
{
  memcpy(percent100, percent0, sizeof(uint32_t)*4);

  TIMER_CH0CV(timer->port) = (uint32_t)(timer->period * percent100[0] / 100);
  TIMER_CH1CV(timer->port) = (uint32_t)(timer->period * percent100[1] / 100);
  TIMER_CH2CV(timer->port) = (uint32_t)(timer->period * percent100[2] / 100);
  TIMER_CH3CV(timer->port) = (uint32_t)(timer->period * percent100[3] / 100);
}





/*****************************************************************************
 *                          PWM In
 *****************************************************************************/
//Only timer1,timer2,timer3,timer4
static void capture_handle(void *param, uint32_t status)
{
  HAL_PWMIn *pwm_in = (HAL_PWMIn*)param;
  
  if(timer_interrupt_flag_get(pwm_in->timer->port, TIMER_INT_FLAG_CH0) != RESET) {
    timer_interrupt_flag_clear(pwm_in->timer->port, TIMER_INT_FLAG_CH0);
    pwm_in->ch[0].captrue[pwm_in->ch[0].index++] = timer_channel_capture_value_register_read(pwm_in->timer->port, TIMER_CH_0) + 1;
    if(pwm_in->ch[0].index == 1) { //Captrued the first rising edge
      if(pwm_in->ch[0].only_freq) {
        pwm_in->ch[0].index++;     //skip falling edge
      } else {
        TIMER_CHCTL2(pwm_in->timer->port) |= (uint32_t)(TIMER_CHCTL2_CH0P);   //Change to capture the first falling edge
      }
    } else if(pwm_in->ch[0].index == 2) { //Captrued the first falling edge
      TIMER_CHCTL2(pwm_in->timer->port) &= ~(uint32_t)(TIMER_CHCTL2_CH0P);    //Change to capture the second rising edge
    } else if(pwm_in->ch[0].index == 3) { //Captrued the second rising edge
      if(!pwm_in->ch[0].only_freq) {
        pwm_in->ch[0].width = pwm_in->ch[0].captrue[1] - pwm_in->ch[0].captrue[0];
         if(pwm_in->ch[0].width < 0) {
           pwm_in->ch[0].width += pwm_in->timer->period;
         }
      } else {
        pwm_in->ch[0].width = pwm_in->ch[0].period / 2;  //always half period
      }
      pwm_in->ch[0].period = pwm_in->ch[0].captrue[2] - pwm_in->ch[0].captrue[0];
      if(pwm_in->ch[0].period < 0) {
        pwm_in->ch[0].period += pwm_in->timer->period;
      }
      pwm_in->ch[0].freq100 = (pwm_in->clock() * 100) / pwm_in->ch[0].period;
      pwm_in->ch[0].freq = pwm_in->ch[0].freq100 / 100;
      pwm_in->ch[0].updated = true;
       
      //Only first captrue need pwm_in->ch[0].index = 0
      pwm_in->ch[0].captrue[0] = pwm_in->ch[0].captrue[2];
      if(pwm_in->ch[0].only_freq) {
        pwm_in->ch[0].index = 2;
      } else {
        pwm_in->ch[0].index = 1;
        TIMER_CHCTL2(pwm_in->timer->port) |= (uint32_t)(TIMER_CHCTL2_CH0P);   //Change to capture the first falling edge
      }
    } 
  }
  if(timer_interrupt_flag_get(pwm_in->timer->port, TIMER_INT_FLAG_CH1) != RESET) {
    timer_interrupt_flag_clear(pwm_in->timer->port, TIMER_INT_FLAG_CH1);
    pwm_in->ch[1].captrue[pwm_in->ch[1].index++] = timer_channel_capture_value_register_read(pwm_in->timer->port, TIMER_CH_1) + 1;
    if(pwm_in->ch[1].index == 1) { //Captrued the first rising edge
      if(pwm_in->ch[1].only_freq) {
        pwm_in->ch[1].index++;     //skip falling edge
      } else {
        TIMER_CHCTL2(pwm_in->timer->port) |= (uint32_t)(TIMER_CHCTL2_CH1P);   //Change to capture the first falling edge
      }
    } else if(pwm_in->ch[1].index == 2) { //Captrued the first falling edge
      TIMER_CHCTL2(pwm_in->timer->port) &= ~(uint32_t)(TIMER_CHCTL2_CH1P);    //Change to capture the second rising edge
    } else if(pwm_in->ch[1].index == 3) { //Captrued the second rising edge
      if(!pwm_in->ch[1].only_freq) {
        pwm_in->ch[1].width = pwm_in->ch[1].captrue[1] - pwm_in->ch[1].captrue[0];
         if(pwm_in->ch[1].width < 0) {
           pwm_in->ch[1].width += pwm_in->timer->period;
         }
      } else {
        pwm_in->ch[1].width = pwm_in->ch[1].period / 2;  //always half period
      }
      pwm_in->ch[1].period = pwm_in->ch[1].captrue[2] - pwm_in->ch[1].captrue[0];
      if(pwm_in->ch[1].period < 0) {
        pwm_in->ch[1].period += pwm_in->timer->period;
      }
      pwm_in->ch[1].freq100 = (pwm_in->clock() * 100) / pwm_in->ch[1].period;
      pwm_in->ch[1].freq = pwm_in->ch[1].freq100 / 100;
      pwm_in->ch[1].updated = true;
       
      //Only first captrue need pwm_in->ch[1].index = 0
      pwm_in->ch[1].captrue[0] = pwm_in->ch[1].captrue[2];
      if(pwm_in->ch[1].only_freq) {
        pwm_in->ch[1].index = 2;
      } else {
        pwm_in->ch[1].index = 1;
        TIMER_CHCTL2(pwm_in->timer->port) |= (uint32_t)(uint32_t)(TIMER_CHCTL2_CH1P);   //Change to capture the first falling edge
      }
    } 
  }
  if(timer_interrupt_flag_get(pwm_in->timer->port, TIMER_INT_FLAG_CH2) != RESET) {
    timer_interrupt_flag_clear(pwm_in->timer->port, TIMER_INT_FLAG_CH2);
    pwm_in->ch[2].captrue[pwm_in->ch[2].index++] = timer_channel_capture_value_register_read(pwm_in->timer->port, TIMER_CH_2) + 1;
    if(pwm_in->ch[2].index == 1) { //Captrued the first rising edge
      if(pwm_in->ch[2].only_freq) {
        pwm_in->ch[2].index++;     //skip falling edge
      } else {
        TIMER_CHCTL2(pwm_in->timer->port) |= (uint32_t)(TIMER_CHCTL2_CH2P);   //Change to capture the first falling edge
      }
    } else if(pwm_in->ch[2].index == 2) { //Captrued the first falling edge
      TIMER_CHCTL2(pwm_in->timer->port) &= ~(uint32_t)(TIMER_CHCTL2_CH2P);    //Change to capture the second rising edge
    } else if(pwm_in->ch[2].index == 3) { //Captrued the second rising edge
      if(!pwm_in->ch[2].only_freq) {
        pwm_in->ch[2].width = pwm_in->ch[2].captrue[1] - pwm_in->ch[2].captrue[0];
         if(pwm_in->ch[2].width < 0) {
           pwm_in->ch[2].width += pwm_in->timer->period;
         }
      } else {
        pwm_in->ch[2].width = pwm_in->ch[2].period / 2;  //always half period
      }
      pwm_in->ch[2].period = pwm_in->ch[2].captrue[2] - pwm_in->ch[2].captrue[0];
      if(pwm_in->ch[2].period < 0) {
        pwm_in->ch[2].period += pwm_in->timer->period;
      }
      pwm_in->ch[2].freq100 = (pwm_in->clock() * 100) / pwm_in->ch[2].period;
      pwm_in->ch[2].freq = pwm_in->ch[2].freq100 / 100;
      pwm_in->ch[2].updated = true;
       
      //Only first captrue need pwm_in->ch[2].index = 0
      pwm_in->ch[2].captrue[0] = pwm_in->ch[2].captrue[2];
      if(pwm_in->ch[2].only_freq) {
        pwm_in->ch[2].index = 2;
      } else {
        pwm_in->ch[2].index = 1;
        TIMER_CHCTL2(pwm_in->timer->port) |= (uint32_t)(uint32_t)(TIMER_CHCTL2_CH2P);   //Change to capture the first falling edge
      }
    } 
  }
  if(timer_interrupt_flag_get(pwm_in->timer->port, TIMER_INT_FLAG_CH3) != RESET) {
    timer_interrupt_flag_clear(pwm_in->timer->port, TIMER_INT_FLAG_CH3);
    pwm_in->ch[3].captrue[pwm_in->ch[3].index++] = timer_channel_capture_value_register_read(pwm_in->timer->port, TIMER_CH_3) + 1;
    if(pwm_in->ch[3].index == 1) { //Captrued the first rising edge
      if(pwm_in->ch[3].only_freq) {
        pwm_in->ch[3].index++;     //skip falling edge
      } else {
        TIMER_CHCTL2(pwm_in->timer->port) |= (uint32_t)(TIMER_CHCTL2_CH3P);   //Change to capture the first falling edge
      }
    } else if(pwm_in->ch[3].index == 2) { //Captrued the first falling edge
      TIMER_CHCTL2(pwm_in->timer->port) &= ~(uint32_t)(TIMER_CHCTL2_CH3P);    //Change to capture the second rising edge
    } else if(pwm_in->ch[3].index == 3) { //Captrued the second rising edge
      if(!pwm_in->ch[3].only_freq) {
        pwm_in->ch[3].width = pwm_in->ch[3].captrue[1] - pwm_in->ch[3].captrue[0];
         if(pwm_in->ch[3].width < 0) {
           pwm_in->ch[3].width += pwm_in->timer->period;
         }
      } else {
        pwm_in->ch[3].width = pwm_in->ch[3].period / 2;  //always half period
      }
      pwm_in->ch[3].period = pwm_in->ch[3].captrue[2] - pwm_in->ch[3].captrue[0];
      if(pwm_in->ch[3].period < 0) {
        pwm_in->ch[3].period += pwm_in->timer->period;
      }
      pwm_in->ch[3].freq100 = (pwm_in->clock() * 100) / pwm_in->ch[3].period;
      pwm_in->ch[3].freq = pwm_in->ch[3].freq100 / 100;
      pwm_in->ch[3].updated = true;
       
      //Only first captrue need pwm_in->ch[3].index = 0
      pwm_in->ch[3].captrue[0] = pwm_in->ch[3].captrue[2];
      if(pwm_in->ch[3].only_freq) {
        pwm_in->ch[3].index = 2;
      } else {
        pwm_in->ch[3].index = 1;
        TIMER_CHCTL2(pwm_in->timer->port) |= (uint32_t)(uint32_t)(TIMER_CHCTL2_CH3P);   //Change to capture the first falling edge
      }
    } 
  }
}
/*
*/
bool HAL_PWMIn::init(HAL_Timer *timer0, uint32_t cfg0)
{
  timer = timer0;
  cfg = cfg0;
  if(timer->port == TIMER1) {
    timer->attach_irq(capture_handle, this);
  } else if(timer->port == TIMER2) {
    timer->attach_irq(capture_handle, this);
  } else if(timer->port == TIMER3) {
    timer->attach_irq(capture_handle, this);
  } else if(timer->port == TIMER4) {
    timer->attach_irq(capture_handle, this);
  } else {
    return false;
  }
  return config(cfg);
}
/*
*/
bool HAL_PWMIn::config(uint32_t cfg0)
{
  cfg &= ~HPWM_CFG_MASK;
  cfg |= cfg0 & HPWM_CFG_MASK;

  /* OC config */
  uint32_t tmp = HPWM_CFG_EXTRACT(cfg, CH);
  bool only_freq = HPWM_CFG_EXTRACT(cfg, CAPTRUE) == HPWM_CAPTRUE(FREQ);
  if(tmp & HPWM_CH(0)) { 
    ch[0].only_freq = only_freq;
    /* reset the CH0EN bit */
    TIMER_CHCTL2(timer->port) &= (~(uint32_t)TIMER_CHCTL2_CH0EN);
    /* reset the CH0P and CH0NP bits */
    TIMER_CHCTL2(timer->port) &= (~(uint32_t)(TIMER_CHCTL2_CH0P | TIMER_CHCTL2_CH0NP));
    /* set the CH0P and CH0NP bits */
    TIMER_CHCTL2(timer->port) |= ((uint32_t)0x00 << 1);  //Input capture is done on a rising edge
    /* reset the CH0MS bit */
    TIMER_CHCTL0(timer->port) &= (~(uint32_t)TIMER_CHCTL0_CH0MS);
    /* set the CH0MS bit */
    TIMER_CHCTL0(timer->port) |= (uint32_t)0x01;  //Channel 0 is configured as input, IS0 is connected to CI0FE0 
    /* reset the CH0CAPFLT bit */
    TIMER_CHCTL0(timer->port) &= (~(uint32_t)TIMER_CHCTL0_CH0CAPFLT);
    /* set the CH0CAPFLT bit */
    TIMER_CHCTL0(timer->port) |= ((uint32_t)0x00 << 4);  //Filter disabled
    /* set the CH0EN bit */
    TIMER_CHCTL2(timer->port) |= (uint32_t)TIMER_CHCTL2_CH0EN;
    
    /* Prescaler disable, capture is done on each channel input edge */
    TIMER_CHCTL0(timer->port) &= (~(uint32_t)TIMER_CHCTL0_CH0CAPPSC);
    
    /* clear channel 0 interrupt bit */
    timer_interrupt_flag_clear(timer->port, TIMER_INT_CH0);
    /* channel 0 interrupt enable */
    timer_interrupt_enable(timer->port, TIMER_INT_CH0);
    
  } 
  if(tmp & HPWM_CH(1)) { 
    ch[1].only_freq = only_freq;
    /* reset the CH1EN bit */
    TIMER_CHCTL2(timer->port) &= (~(uint32_t)TIMER_CHCTL2_CH1EN);
    /* reset the CH1P and CH1NP bits */
    TIMER_CHCTL2(timer->port) &= (~(uint32_t)(TIMER_CHCTL2_CH1P | TIMER_CHCTL2_CH1NP));
    /* set the CH1P and CH1NP bits */
    TIMER_CHCTL2(timer->port) |= ((uint32_t)0x00 << 5); //Input capture is done on a rising edge
    /* reset the CH1MS bit */
    TIMER_CHCTL0(timer->port) &= (~(uint32_t)TIMER_CHCTL0_CH1MS);
    /* set the CH1MS bit */
    TIMER_CHCTL0(timer->port) |= ((uint32_t)0x01 << 8);  //Channel 1 is configured as input, IS1 is connected to CI1FE1 
    /* reset the CH1CAPFLT bit */
    TIMER_CHCTL0(timer->port) &= (~(uint32_t)TIMER_CHCTL0_CH1CAPFLT);
    /* set the CH1CAPFLT bit */
    TIMER_CHCTL0(timer->port) |= ((uint32_t)0x00 << 12);  //Filter disabled
    /* set the CH1EN bit */
    TIMER_CHCTL2(timer->port) |= (uint32_t)TIMER_CHCTL2_CH1EN;
    
    /* Prescaler disable, capture is done on each channel input edge */
    TIMER_CHCTL0(timer->port) &= (~(uint32_t)TIMER_CHCTL0_CH1CAPPSC);
    
    /* clear channel 1 interrupt bit */
    timer_interrupt_flag_clear(timer->port, TIMER_INT_CH1);
    /* channel 1 interrupt enable */
    timer_interrupt_enable(timer->port, TIMER_INT_CH1);
    
  } 
  if(tmp & HPWM_CH(2)) { 
    ch[2].only_freq = only_freq;
    /* reset the CH2EN bit */
    TIMER_CHCTL2(timer->port) &= (~(uint32_t)TIMER_CHCTL2_CH2EN);
    /* reset the CH2P and CH2NP bits */
    TIMER_CHCTL2(timer->port) &= (~(uint32_t)(TIMER_CHCTL2_CH2P | TIMER_CHCTL2_CH2NP));
    /* set the CH2P and CH2NP bits */
    TIMER_CHCTL2(timer->port) |= ((uint32_t)0x00 << 9); //Input capture is done on a rising edge
    /* reset the CH2MS bit */
    TIMER_CHCTL1(timer->port) &= (~(uint32_t)TIMER_CHCTL1_CH2MS);
    /* set the CH2MS bit */
    TIMER_CHCTL1(timer->port) |= (uint32_t)0x01;  //Channel 2 is configured as input, IS2 is connected to CI2FE2 
    /* reset the CH2CAPFLT bit */
    TIMER_CHCTL1(timer->port) &= (~(uint32_t)TIMER_CHCTL1_CH2CAPFLT);
    /* set the CH2CAPFLT bit */
    TIMER_CHCTL2(timer->port) |= ((uint32_t)0x00 << 4);  //Filter disabled
    /* set the CH2EN bit */
    TIMER_CHCTL2(timer->port) |= (uint32_t)TIMER_CHCTL2_CH2EN;
    
    /* Prescaler disable, capture is done on each channel input edge */
    TIMER_CHCTL1(timer->port) &= (~(uint32_t)TIMER_CHCTL1_CH2CAPPSC);
    
    /* clear channel 2 interrupt bit */
    timer_interrupt_flag_clear(timer->port, TIMER_INT_CH2);
    /* channel 2 interrupt enable */
    timer_interrupt_enable(timer->port, TIMER_INT_CH2);
    
  } 
  if(tmp & HPWM_CH(3)) { 
    ch[3].only_freq = only_freq;
    /* reset the CH3EN bit */
    TIMER_CHCTL2(timer->port) &= (~(uint32_t)TIMER_CHCTL2_CH3EN);
    /* reset the CH3P and CH3NP bits */
    TIMER_CHCTL2(timer->port) &= (~(uint32_t)(TIMER_CHCTL2_CH3P));
    /* set the CH3P and CH3NP bits */
    TIMER_CHCTL2(timer->port) |= ((uint32_t)0x00 << 13); //Input capture is done on a rising edge
    /* reset the CH3MS bit */
    TIMER_CHCTL1(timer->port) &= (~(uint32_t)TIMER_CHCTL1_CH3MS);
    /* set the CH3MS bit */
    TIMER_CHCTL1(timer->port) |= ((uint32_t)0x01 << 8);  //Channel 3 is configured as input, IS3 is connected to CI3FE3 
    /* reset the CH3CAPFLT bit */
    TIMER_CHCTL1(timer->port) &= (~(uint32_t)TIMER_CHCTL1_CH3CAPFLT);
    /* set the CH3CAPFLT bit */
    TIMER_CHCTL1(timer->port) |= ((uint32_t)0x00 << 12);  //Filter disabled
    /* set the CH3EN bit */
    TIMER_CHCTL2(timer->port) |= (uint32_t)TIMER_CHCTL2_CH3EN;
    
    /* Prescaler disable, capture is done on each channel input edge */
    TIMER_CHCTL1(timer->port) &= (~(uint32_t)TIMER_CHCTL1_CH3CAPPSC);
    
    /* clear channel 3 interrupt bit */
    timer_interrupt_flag_clear(timer->port, TIMER_INT_CH3);
    /* channel 3 interrupt enable */
    timer_interrupt_enable(timer->port, TIMER_INT_CH3);
  }
  return true;
}
